package com.sky.com.sky.service.impl;

import cn.hutool.core.util.StrUtil;
import com.sky.dto.GoodsSalesDTO;
import com.sky.dto.ReportDTO;
import com.sky.entity.Orders;
import com.sky.exception.BusinessException;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.ReportMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.vo.*;
import io.swagger.models.auth.In;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class ReportServiceImpl implements ReportService {

    private final OrderMapper orderMapper;

    private final UserMapper userMapper;
    @Autowired
    ReportMapper reportMapper;

    /**
     * 营业额统计
     *
     * @param begin
     * @param end
     * @return
     **/
    @Override
    public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {
       //1. 拼接一个时间区间 5月1日 - 5月30日
        ArrayList<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while (!begin.equals(end)){
            // +1 天
            end = begin.plusDays(1);
            dateList.add(end);
        }

        //2. 声明 营业额集合
        ArrayList<Double> turnoverList = new ArrayList<>();

        //3. 遍历时间
        for (LocalDate currentDate : dateList) {
            // 3-1 查询当天的营业额
            Double turnover = orderMapper.sumTurnover(Orders.COMPLETED, currentDate);
            //3-2 添加营业额
            if(turnover == null){
                turnover=0d;
            }
            turnoverList.add(turnover);
        }
        //4. 封装并返回vo
        TurnoverReportVO turnoverReportVO = TurnoverReportVO.builder()
                .dateList(StrUtil.join(",", dateList))
                .turnoverList(StrUtil.join(",", turnoverList))
                .build();
        return turnoverReportVO;
    }

    /**
     * 用户统计
     *
     * @param begin
     * @param end
     * @return
     **/
    @Override
    public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
        //参数校验
        if (begin == null || end == null) {
            throw new BusinessException(400, "去烧参数");
        }
        ArrayList<LocalDate> datelist = new ArrayList<>();
        ArrayList<Object> newUserList = new ArrayList<>();
        ArrayList<Object> totalUserList = new ArrayList<>();

        //填充日期数据
        datelist.add(begin);
        while (!begin.equals(end)) {
            //注意重新赋值，否则begin日期不变
            begin = begin.plusDays(1);
            datelist.add(begin);
        }

        /**
         * 1.统计日期范围内用户数量
         * 2.遍历日期集合
         * 2.1 查找当天是否有新增用户数量:有->加入集合 没有->加0
         * 2.2 累计新增用户数量，加入到总用户集合
         *
         * **/
        List<ReportDTO> userList = reportMapper.userStatistics(datelist.get(0), end);
        Integer sum=0;
        for (LocalDate localDate : datelist) {
            //查找当天是否有新增用户数量
            Optional<ReportDTO> optional = userList.stream().filter(userReportDTO -> {
                return userReportDTO.getTime().equals(localDate);
            }).findFirst();
            //有
            if(optional.isPresent()){
                Integer total = Integer.valueOf(optional.get().getTotal().toString());
                newUserList.add(total);
                totalUserList.add(sum+=total);
            }else { //没有
                newUserList.add(0);
                totalUserList.add(sum);
            }
        }
        //封装结果返回
        return UserReportVO.builder()
                .dateList(StringUtils.join(datelist,","))
                .newUserList(StringUtils.join(newUserList,","))
                .totalUserList(StringUtils.join(totalUserList,","))
                .build();
    }


    // 抽取填充日期集合
    private List<LocalDate> getLocalDates(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while (!begin.equals(end)) {
            begin = begin.plusDays(1);
            dateList.add(begin);
        }
        return dateList;
    }

    // 订单统计
    @Override
    public OrderReportVO getOrdersStatistics(LocalDate begin, LocalDate end) {
        //1. 填充日期集合
        List<LocalDate> dateList = getLocalDates(begin, end);
        //2. 声明
        // 2-1 订单数列表
        ArrayList<Integer> orderCountList = new ArrayList<>();
         //2-2 有效订单数列表
        ArrayList<Integer> validOrderCountList = new ArrayList<>();
        //2-3 订单总数
        Integer totalOrderCount=0;
        //2-4 有效订单总数
        Integer validOrderCount=0;
        //3.遍历日期
        for (LocalDate currentDate : dateList) {
            //3-1 查询当天总订单
            Integer countOrder = orderMapper.countOrder(null, currentDate);
            // 3-2 查询当天有效订单
            Integer countValidorder = orderMapper.countOrder(Orders.COMPLETED, currentDate);
            // 3-3 累加总订单
            totalOrderCount += countOrder;
            //3-4 累加有效订单
            validOrderCount += countValidorder;
            // 3-5 添加当天总订单
            orderCountList.add(countOrder);
            // 3-6 添加当天有效订单
            validOrderCountList.add(countValidorder);
        }
        //4. 计算订单完成率
        Double orderCompletionRate=0.0;
        if(validOrderCount > 0 && totalOrderCount>0){
            orderCompletionRate=validOrderCount *1.0 / totalOrderCount;
        }
        //5.封装并返回vo
        return OrderReportVO.builder()
                .dateList(StrUtil.join(",",dateList))
                .orderCompletionRate(orderCompletionRate)
                .orderCountList(StrUtil.join(",",orderCountList))
                .totalOrderCount(totalOrderCount)
                .validOrderCount(validOrderCount)
                .validOrderCountList(StrUtil.join(",",validOrderCountList))
                .build();
    }

    //销量排名
    @Override
    public SalesTop10ReportVO getTop10(LocalDate begin, LocalDate end) {
      //1. 直接调用mapper查询
        List<GoodsSalesDTO> list = orderMapper.getSalesTop10(begin, end);
        //2. 声明商品列表，销量列表
        ArrayList<String> nameList = new ArrayList<>();
        ArrayList<Integer> numberList = new ArrayList<>();
        //3. 遍历结果集
        for (GoodsSalesDTO goodsSalesDTO : list) {
            //3-1 添加名称
            nameList.add(goodsSalesDTO.getName());
            //3-2 添加销量
            numberList.add(goodsSalesDTO.getNumber());
        }
        //4. 封装并返回vo
        return SalesTop10ReportVO.builder()
                .nameList(StrUtil.join("，",nameList))
                .numberList(StrUtil.join(",",numberList))
                .build();
    }

    /**
     * 订单统计
     * @param begin
     * @param end
     * @return
     * **/
    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
       /**
        * 1.获取日期集合
        * 2.查询日期范围内每天的全部订单数量
        *   查询日期范围内每天的订单数量
        *  3.准备集合：用于保存每天订单总数量、每天有效订单数量
        *  4.准备统计计数: 用于统计日期范围内所有订单总量、有效订单总量
        *
        *  5.遍历日期，根据每天日期查找订单数量、有效订单数量、并且累计订单总量，有效订单总量
        *  5.1判断当天是否有订单并累计订单数量、有效订单数量、将数量加入集合
        *  5.2累加订单总量，有效订单总量
        *
        *  6.封装对象返回
        *
        * **/
       //1. 获取日期集合
        ArrayList<LocalDate> dateList = getDateList(begin, end);
        //2。根据 开始日期、结束日期、订单状态 统计每天订单数据
        List<ReportDTO> allOrderList= reportMapper.ordersStatistics(begin,end,null);

        List<ReportDTO> validOrderList= reportMapper.ordersStatistics(begin,end,Orders.COMPLETED);

        //3. 准备集合，保存每天订单总数量、每天有效订单量
        ArrayList<Integer>  allOrderCountList  = new ArrayList<>();
        ArrayList<Integer> validOrderCountList = new ArrayList<>();

        //4. 准备统计计数，统计日期范围内所有订单数量、有效订单总量
        //注意：基本类型以及包装类都是值传递，类、接口、数组才是引用传递
        int totalOrderCount=0;
        int validOrderCount=0;
        //5.遍历日期，根据每天日期查找订单数量、有效订单数量，并且累计订单总量，有效订单总量
        for (LocalDate localDate : dateList) {
            totalOrderCount=dataToList(allOrderList,allOrderCountList,localDate,totalOrderCount);
            validOrderCount=dataToList(validOrderList,validOrderCountList,localDate,validOrderCount);
        }

        //6.封装vo对象并返回
        return OrderReportVO.builder()
                .dateList(StringUtils.join(dateList,","))
                .orderCountList(StringUtils.join(allOrderCountList,","))
                .validOrderCountList(StringUtils.join(validOrderCountList,","))
                .totalOrderCount(totalOrderCount)
                .validOrderCount(validOrderCount)
                .orderCompletionRate(validOrderCount * 1.0 / totalOrderCount)
                .build();
    }

    /**
     * 查询指定时间区间内的 已完成的订单 销量排名top10
     * @param begin
     * @parm end
     * @return
     * **/
    @Override
    public SalesTopnVO top10(LocalDate begin, LocalDate end) {
       //查询 已完成 top10销量的商品(菜品+套餐)
       List<GoodsSalesDTO> goodsSalesDTOList= reportMapper.top10(begin,end);

       //获取名称集合
        List<String> nameList = goodsSalesDTOList.stream().map(goodsSalesDTO -> {
            return goodsSalesDTO.getName();
        }).collect(Collectors.toList());

        //获取销量集合
        List<Integer> numberList = goodsSalesDTOList.stream()
                .map(goodsSalesDTO -> goodsSalesDTO.getNumber())
                .collect(Collectors.toList());

        return SalesTopnVO.builder()
                .nameList(StringUtils.join(nameList,","))
                .numberList(StringUtils.join(numberList,","))
                .build();
    }

    /**
     * 根据每天日期查找订单数量 并且累加计数
     * @param sourceDataList
     * @param targetNumList
     * @param date
     * @param sum
     * **/
    private int dataToList(List<ReportDTO> sourceDataList, ArrayList<Integer> targetNumList, LocalDate date, int sum) {
        //根据日期在集合中查找对象
        Optional<ReportDTO> optional = sourceDataList.stream().filter(reportDTO -> {
            return reportDTO.getTime().equals(date);
        }).findFirst();
        //对应日期有结果
        if(optional.isPresent()){
            //获取日期对应的订单数量
            Integer num = Integer.valueOf(optional.get().getTotal().toString());
            //添加到集合中
            targetNumList.add(num);
            //数量相加(引用类型才会该彼岸属性值)
            sum += num;
        }else {//对应日期没有结果
            targetNumList.add(0);
        }
        return sum;
    }


    /**
     * 根据开始日期和结束日期返回日期集合
     * @param begin
     * @param end
     * @retuen
     * **/
    private ArrayList<LocalDate> getDateList(LocalDate begin,LocalDate end){
        if(begin == null || end == null){
            throw new BusinessException(400,"缺少参数");
        }

        ArrayList<LocalDate> dateList = new ArrayList<>();

        //添加开始日期
        dateList.add(begin);
        while (!begin.equals(end)){
            //日期+1
            begin = begin.plusDays(1);
            dateList.add(begin);
        }
        return dateList;
    }



}